// threadtest.cc 
//	Simple test case for the threads assignment.
//
//	Create two threads, and have them context switch
//	back and forth between themselves by calling Thread::Yield, 
//	to illustratethe inner workings of the thread system.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include "copyright.h"
#include "system.h"

// testnum is set in main.cc
int testnum = 1;
int money = 100;
int eggNum = 0;
int eggRound = 4000;
int coworkerNum = 0;
int readcount = 0;
int rwRound = 4000;
//----------------------------------------------------------------------
// SimpleThread
// 	Loop 5 times, yielding the CPU to another ready thread 
//	each iteration.
//
//	"which" is simply a number identifying the thread, for debugging
//	purposes.
//----------------------------------------------------------------------

void
SimpleThread(int which)
{
    int num;
    
    for (num = 0; num < 5; num++) {
	printf("*** thread %d looped %d times\n", which, num);
        //currentThread->Yield();
        interrupt->OneTick();
    }
}
void
daemonThread(int which)
{
    int num;
    
    for (num = 0; num < 50000; num++) {
	printf("*** thread %d looped %d times\n", which, num);
        //currentThread->Yield();
        interrupt->OneTick();
    }
}
void
moneyThread(int which)
{
    lock->Acquire();
    int num;
    for (num = 0; num < 50; num++) {
	printf("*** thread %d looped %d times\n", which, num);
        //currentThread->Yield();
        interrupt->OneTick();
    }
    lock->Release();
}
void
cuterThread(int which)
{
  int eatTime=99999;
  while(eggRound) {
    eggRound--;
    lock->Acquire();
    if(eggNum>0) {
        printf("(%d said:)There are my egg(%d),I eat one!\n",which,eggNum);
        eggNum--;
        eggCondition->Broadcast(lock);
	eatTime=99999;
	while(eatTime>0)//eating......
	    eatTime--;
    }
    interrupt->OneTick();
    
    lock->Release();
  }
}
void
makerThread(int which)
{
  while(eggRound) {
    eggRound--;
    lock->Acquire();
    while(eggNum>=10) {
	printf("(%d said:)So many egg(%d),I don't make egg any more!\n",which,eggNum);
        eggCondition->Wait(lock);
    }
    printf("(%d said:)Not enough eggs(%d)!I make one!\n",which,eggNum);
    eggNum++;

    interrupt->OneTick();
    
    lock->Release();
  }
}
void
coworkThread(int which)
{
    lock->Acquire();
    if(3>coworkerNum)
    {
	coworkerNum++;
	if(3>coworkerNum)
	{
	    while(3>coworkerNum) {
		printf("(%d said:)Not enough coworker(%d),I can't make it!\n",which,coworkerNum);
		coworkCondition->Wait(lock);
	    }
	}
	else
	{
		printf("(%d said:)Now, we have (%d) guys!let's go!\n",which,coworkerNum);
		coworkCondition->Broadcast(lock);
	}
    }
    else
    {
	printf("(%d said:)OK guys(%d)!I'll join you!\n",which,coworkerNum);
	coworkerNum++;
    }
    printf("(%d said:)I get it!\n",which,coworkerNum);

    interrupt->OneTick();
    
    lock->Release();
  
}

void reader(int which)
{
     while ( rwRound )
    {
	rwRound--;
        rdcntmutex->P();
         if ( readcount==0)
           fmutex->P();
        readcount = readcount + 1 ;
        rdcntmutex->V();
         // Do read operation   
	printf("(%d said:)I read now!\n",which);
        rdcntmutex->P();
        readcount = readcount - 1 ;
         if ( readcount==0)
           fmutex->V();
        rdcntmutex->V();
	interrupt->OneTick();
    }
}
void writer(int which)
{
     while ( rwRound )
    {
	rwRound--;
        fmutex->P();
         // Do write operation  
	printf("(%d said:)I write now!\n",which);
        fmutex->V();
	interrupt->OneTick();
    }
}
//----------------------------------------------------------------------
// ThreadTest1
// 	Set up a ping-pong between two threads, by forking a thread 
//	to call SimpleThread, and then calling SimpleThread ourselves.
//----------------------------------------------------------------------

void
ThreadTest1()
{
printf("interrupt level is %d\n",interrupt->getLevel());

    DEBUG('t', "Entering ThreadTest1");
printf("want to create daemon\n");
    Thread *daemon = new Thread("daemon(me back up!)");
    daemon->setPriority(200);
    daemon->Fork(daemonThread, -1);
printf("begin:");scheduler->Print();printf("end\n");
//preemptive test
printf("want to create t1\n");
    Thread *t1 = new Thread("t1");
    t1->setPriority(19);
    t1->Fork(SimpleThread, 1);
printf("begin:");scheduler->Print();printf("end\n");
printf("want to create t2\n");
    Thread *t2 = new Thread("t2");
    t2->setPriority(16);
    t2->Fork(SimpleThread, 2);
printf("begin:");scheduler->Print();printf("end\n");
printf("want to create t3\n");
   Thread *t3 = new Thread("t3");
    t3->setPriority(15);
    t3->Fork(SimpleThread, 3);
printf("begin:");scheduler->Print();printf("end\n");
//lock test
printf("want to create t4-teller\n");
   Thread *t4 = new Thread("t4");
    t4->setPriority(30);
    t4->Fork(moneyThread, 4);
printf("begin:");scheduler->Print();printf("end\n");
printf("want to create t5-accountant\n");
   Thread *t5 = new Thread("t5");
    t5->setPriority(30);
    t5->Fork(moneyThread, 5);
printf("begin:");scheduler->Print();printf("end\n");

//condition test
printf("want to create t6-cuter1\n");
   Thread *t6 = new Thread("t6");
    t6->setPriority(40);
    t6->Fork(cuterThread, 6);
printf("begin:");scheduler->Print();printf("end\n");
printf("want to create t7-cuter2\n");
   Thread *t7 = new Thread("t7");
    t7->setPriority(40);
    t7->Fork(cuterThread, 7);
printf("begin:");scheduler->Print();printf("end\n");
printf("want to create t8-maker\n");
   Thread *t8 = new Thread("t8");
    t8->setPriority(40);
    t8->Fork(makerThread, 8);
printf("begin:");scheduler->Print();printf("end\n");


//barrier test
printf("want to create t9-cowoker1\n");
   Thread *t9 = new Thread("t9-cowoker1");
    t9->setPriority(50);
    t9->Fork(coworkThread, 9);
printf("begin:");scheduler->Print();printf("end\n");
printf("want to create t10-cowoker2\n");
   Thread *t10 = new Thread("t10-cowoker2");
    t10->setPriority(50);
    t10->Fork(coworkThread, 10);
printf("begin:");scheduler->Print();printf("end\n");
printf("want to create t11-cowoker3\n");
   Thread *t11 = new Thread("t11-cowoker3");
    t11->setPriority(50);
    t11->Fork(coworkThread, 11);
printf("begin:");scheduler->Print();printf("end\n");


//reader and writer test
printf("want to create t12-reader\n");
   Thread *t12 = new Thread("t12-reader1");
    t12->setPriority(60);
    t12->Fork(reader, 12);
printf("begin:");scheduler->Print();printf("end\n");
printf("want to create t13-writer\n");
   Thread *t13 = new Thread("t13-writer");
    t13->setPriority(60);
    t13->Fork(writer, 13);
printf("begin:");scheduler->Print();printf("end\n");

printf("want to SimpleThread(0)\n");
    SimpleThread(0);
printf("begin:");scheduler->Print();printf("end\n");
}

//----------------------------------------------------------------------
// ThreadTest
// 	Invoke a test routine.
//----------------------------------------------------------------------

void
ThreadTest()
{
    switch (testnum) {
    case 1:
	ThreadTest1();
	break;
    default:
	printf("No test specified.\n");
	break;
    }
}

